home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / dvips / afm2tfm.c- < prev    next >
Text File  |  1990-01-27  |  33KB  |  1,210 lines

  1. /*
  2.  *   This program converts AFM files to TeX TFM files, and optionally
  3.  *   to TeX VPL files that retain all kerning and ligature information.
  4.  *   Both files make the characters not normally encoded by TeX available
  5.  *   by character codes greater than 127.
  6.  */
  7.  
  8. /*   (Modified by Don Knuth from Tom Rokicki's pre-VPL version.) */
  9.  
  10. #include <stdio.h>
  11. #ifdef SYSV
  12. #include <string.h>
  13. #else
  14. #include <strings.h>
  15. #endif
  16.  
  17. char *texencoding[] = {
  18.    "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma",
  19.    "Upsilon", "Phi", "Psi", "Omega", "arrowup", "arrowdown", "quotesingle",
  20.    "exclamdown", "questiondown", "dotlessi", "dotlessj", "grave", "acute",
  21.    "caron", "breve", "macron", "ring", "cedilla", "germandbls", "ae", "oe",
  22.    "oslash", "AE", "OE", "Oslash", "space", "exclam", "quotedbl", "numbersign",
  23.    "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright",
  24.    "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one",
  25.    "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon",
  26.    "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C",
  27.    "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
  28.    "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash",
  29.    "bracketright", "circumflex", "underscore", "quoteleft", "a", "b", "c", "d",
  30.    "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
  31.    "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright",
  32.    "tilde", "dieresis" } ;
  33. /*
  34.  *   The above layout corresponds to TeX Typewriter Type and is compatible
  35.  *   with TeX Text because the position of ligatures is immaterial.
  36.  */
  37.  
  38. /*
  39.  *   This is what we store Adobe data in.
  40.  */
  41. struct adobeinfo {
  42.    struct adobeinfo *next ;
  43.    int adobenum, texnum, width ;
  44.    char *adobename ;
  45.    int llx, lly, urx, ury ;
  46.    struct lig *ligs ;
  47.    struct kern *kerns ;
  48.    struct pcc *pccs ;
  49.    int wptr, hptr, dptr, iptr ;
  50. } *adobechars, *adobeptrs[256], *texptrs[256],
  51.   *uppercase[256], *lowercase[256] ;
  52. struct lig {
  53.    struct lig *next ;
  54.    char *succ, *sub ;
  55. } ;
  56. struct kern {
  57.    struct kern *next ;
  58.    char *succ ;
  59.    int delta ;
  60. } ;
  61. struct pcc {
  62.    struct pcc *next ;
  63.    char * partname ;
  64.    int xoffset, yoffset ;
  65. } ;
  66.  
  67. FILE *afmin, *vplout, *tfmout ;
  68. char inname[200], outname[200] ; /* names of input and output files */
  69. char buffer[255]; /* input buffer (modified while parsing) */
  70. char obuffer[255] ; /* unmodified copy of input buffer */
  71. char *param ; /* current position in input buffer */
  72. char *fontname = "Unknown" ;
  73. char *codingscheme = "Unspecified" ;
  74. float italicangle = 0.0 ;
  75. char fixedpitch ;
  76. char makevpl ;
  77. int xheight = 400 ;
  78. int fontspace ;
  79. int bc, ec ;
  80. long cksum ;
  81. float efactor = 1.0, slant = 0.0 ;
  82. double newslant ;
  83. char titlebuf[100] ;
  84.  
  85. void
  86. error(s)
  87. register char *s ;
  88. {
  89.    (void)fprintf(stderr, "%s\n", s) ;
  90.    if (obuffer[0]) {
  91.       (void)fprintf(stderr, "%s\n", obuffer) ;
  92.       while (param > buffer) {
  93.          (void)fprintf(stderr, " ") ;
  94.          param-- ;
  95.       }
  96.       (void)fprintf(stderr, "^\n") ;
  97.    }
  98.    if (*s == '!')
  99.       exit(1) ;
  100. }
  101.  
  102. int
  103. transform(x,y)
  104.    register int x,y ;
  105. {
  106.    register double acc ;
  107.    acc = efactor * x + slant *y ;
  108.    return (int)(acc>=0? acc+0.5 : acc-0.5 ) ;
  109. }
  110.  
  111. int
  112. getline() {
  113.    register char *p ;
  114.    register int c ;
  115.  
  116.    param = buffer ;
  117.    for (p=buffer; (c=getc(afmin)) != EOF && c != 10;)
  118.       *p++ = c ;
  119.    *p = 0 ;
  120.    (void)strcpy(obuffer, buffer) ;
  121.    if (p == buffer && c == EOF)
  122.       return(0) ;
  123.    else
  124.       return(1) ;
  125. }
  126.  
  127. char *interesting[] = { "FontName", "ItalicAngle", "IsFixedPitch",
  128.    "XHeight", "C", "KPX", "CC", "EncodingScheme", NULL} ; 
  129. #define FontName (0)
  130. #define ItalicAngle (1)
  131. #define IsFixedPitch (2)
  132. #define XHeight (3)
  133. #define C (4)
  134. #define KPX (5)
  135. #define CC (6)
  136. #define EncodingScheme (7)
  137. #define NONE (-1)
  138. int
  139. interest(s)
  140. char *s ;
  141. {
  142.    register char **p ;
  143.    register int n ;
  144.  
  145.    for (p=interesting, n=0; *p; p++, n++)
  146.       if (strcmp(s, *p)==0)
  147.          return(n) ;
  148.    return(NONE) ;
  149. }
  150.  
  151. char *
  152. mymalloc(len)
  153. int len ;
  154. {
  155.    register char *p ;
  156.    extern char *malloc() ;
  157.  
  158.    p = malloc((unsigned)len) ;
  159.    if (p==NULL)
  160.       error("! out of memory") ;
  161.    return(p) ;
  162. }
  163.  
  164. char *
  165. paramnewstring() {
  166.    register char *p, *q ;
  167.  
  168.    p = param ;
  169.    while (*p > ' ')
  170.       p++ ;
  171.    q = mymalloc((int)(p-param+1)) ;
  172.    if (*p != 0)
  173.       *p++ = 0 ;
  174.    (void)strcpy(q, param) ;
  175.    while (*p && *p <= ' ')
  176.       p++ ;
  177.    param = p ;
  178.    return(q) ;
  179. }
  180.  
  181. char *
  182. paramstring() {
  183.    register char *p, *q ;
  184.  
  185.    p = param ;
  186.    while (*p > ' ')
  187.       p++ ;
  188.    q = param ;
  189.    if (*p != 0)
  190.       *p++ = 0 ;
  191.    while (*p && *p <= ' ')
  192.       p++ ;
  193.    param = p ;
  194.    return(q) ;
  195. }
  196.  
  197. int
  198. paramnum() {
  199.    register char *p ;
  200.    int i ;
  201.  
  202.    p = paramstring() ;
  203.    if (sscanf(p, "%d", &i) != 1)
  204.       error("! integer expected") ;
  205.    return(i) ;
  206. }
  207.  
  208. float
  209. paramfloat() {
  210.    register char *p ;
  211.    float i ;
  212.  
  213.    p = paramstring() ;
  214.    if (sscanf(p, "%f", &i) != 1)
  215.       error("! number expected") ;
  216.    return(i) ;
  217. }
  218.  
  219. struct adobeinfo *
  220. newchar() {
  221.    register struct adobeinfo *ai ;
  222.  
  223.    ai = (struct adobeinfo *)mymalloc(sizeof(struct adobeinfo)) ;
  224.    ai->adobenum = -1 ;
  225.    ai->texnum = -1 ;
  226.    ai->width = -1 ;
  227.    ai->adobename = NULL ;
  228.    ai->llx = -1 ;
  229.    ai->lly = -1 ;
  230.    ai->urx = -1 ;
  231.    ai->ury = -1 ;
  232.    ai->ligs = NULL ;
  233.    ai->kerns = NULL ;
  234.    ai->pccs = NULL ;
  235.    ai->next = adobechars ;
  236.    adobechars = ai ;
  237.    return(ai) ;
  238. }
  239.  
  240. struct kern *
  241. newkern() {
  242.    register struct kern *nk ;
  243.  
  244.    nk = (struct kern *)mymalloc(sizeof(struct kern)) ;
  245.    nk->next = NULL ;
  246.    nk->succ = NULL ;
  247.    nk->delta = 0 ;
  248.    return(nk) ;
  249. }
  250.  
  251. struct pcc *
  252. newpcc() {
  253.    register struct pcc *np ;
  254.  
  255.    np = (struct pcc *)mymalloc(sizeof(struct pcc)) ;
  256.    np->next = NULL ;
  257.    np->partname = NULL ;
  258.    np->xoffset = 0 ;
  259.    np->yoffset = 0 ;
  260.    return(np) ;
  261. }
  262.  
  263. struct lig *
  264. newlig() {
  265.    register struct lig *nl ;
  266.  
  267.    nl = (struct lig *)mymalloc(sizeof(struct lig)) ;
  268.    nl->next = NULL ;
  269.    nl->succ = NULL ;
  270.    nl->sub = NULL ;
  271.    return(nl) ;
  272. }
  273.  
  274. void
  275. expect(s)
  276. char *s ;
  277. {
  278.    if (strcmp(paramstring(), s) != 0) {
  279.       (void)fprintf(stderr, "%s expected: ", s) ;
  280.       error("! syntax error") ;
  281.    }
  282. }
  283.  
  284. void
  285. handlechar() { /* an input line beginning with C */
  286.    register struct adobeinfo *ai ;
  287.    register struct lig *nl ;
  288.  
  289.    ai = newchar() ;
  290.    ai->adobenum = paramnum() ;
  291.    expect(";") ;
  292.    expect("WX") ;
  293.    ai->width = transform(paramnum(),0) ;
  294.    if (ai->adobenum >= 0) {
  295.       adobeptrs[ai->adobenum] = ai ;
  296.       cksum = (cksum<<1) ^ ai->width ;
  297.    }
  298.    expect(";") ;
  299.    expect("N") ;
  300.    ai->adobename = paramnewstring() ;
  301.    expect(";") ;
  302.    expect("B") ;
  303.    ai->llx = paramnum() ;
  304.    ai->lly = paramnum() ;
  305.    ai->llx = transform(ai->llx, ai->lly) ;
  306.    ai->urx = paramnum() ;
  307.    ai->ury = paramnum() ;
  308.    ai->urx = transform(ai->urx, ai->ury) ;
  309.    expect(";") ;
  310. /* Now look for ligatures (which aren't present in fixedpitch fonts) */
  311.    while (*param == 'L') {
  312.       expect("L") ;
  313.       nl = newlig() ;
  314.       nl->succ = paramnewstring() ;
  315.       nl->sub = paramnewstring() ;
  316.       nl->next = ai->ligs ;
  317.       ai->ligs = nl ;
  318.       expect(";") ;
  319.    }
  320.    if (strcmp(ai->adobename, "space")==0) {
  321.       fontspace = ai->width ;
  322.       nl = newlig() ;        /* space will act as zero-width Polish crossbar */
  323.       nl->succ = "l" ;       /* when used by plain TeX's \l or \L macros */
  324.       nl->sub = "lslash" ;
  325.       nl->next = ai->ligs ;
  326.       ai->ligs = nl ;
  327.       nl = newlig() ;
  328.       nl->succ = "L" ;
  329.       nl->sub = "Lslash" ;
  330.       nl->next = ai->ligs ;
  331.       ai->ligs = nl ;
  332.    } else if (strcmp(ai->adobename, "question")==0) {
  333.       nl = newlig() ;
  334.       nl->succ = "quoteleft" ;
  335.       nl->sub = "questiondown" ;
  336.       nl->next = ai->ligs ;
  337.       ai->ligs = nl ;
  338.    } else if (strcmp(ai->adobename, "exclam")==0) {
  339.       nl = newlig() ;
  340.       nl->succ = "quoteleft" ;
  341.       nl->sub = "exclamdown" ;
  342.       nl->next = ai->ligs ;
  343.       ai->ligs = nl ;
  344.    } else if (! fixedpitch) {
  345.       if (strcmp(ai->adobename, "hyphen")==0) {
  346.          nl = newlig() ;
  347.          nl->succ = "hyphen" ;
  348.          nl->sub = "endash" ;
  349.          nl->next = ai->ligs ;
  350.          ai->ligs = nl ;
  351.       } else if (strcmp(ai->adobename, "endash")==0) {
  352.          nl = newlig() ;
  353.          nl->succ = "hyphen" ;
  354.          nl->sub = "emdash" ;
  355.          nl->next = ai->ligs ;
  356.          ai->ligs = nl ;
  357.       } else if (strcmp(ai->adobename, "quoteleft")==0) {
  358.          nl = newlig() ;
  359.          nl->succ = "quoteleft" ;
  360.          nl->sub = "quotedblleft" ;
  361.          nl->next = ai->ligs ;
  362.          ai->ligs = nl ;
  363.       } else if (strcmp(ai->adobename, "quoteright")==0) {
  364.          nl = newlig() ;
  365.          nl->succ = "quoteright" ;
  366.          nl->sub = "quotedblright" ;
  367.          nl->next = ai->ligs ;
  368.          ai->ligs = nl ;
  369.       }
  370.    }
  371. }
  372.  
  373. struct adobeinfo *
  374. findadobe(p)
  375. char *p ;
  376. {
  377.    register struct adobeinfo *ai ;
  378.  
  379.    for (ai=adobechars; ai; ai = ai->next)
  380.       if (strcmp(p, ai->adobename)==0)
  381.          return(ai) ;
  382.    return(NULL) ;
  383. }
  384.  
  385. /* We ignore kerns before and after space characters, because (1) TeX
  386.  * is using the space only for Polish ligatures, and (2) TeX's
  387.  * boundarychar mechanisms are not oriented to kerns (they apply
  388.  * to both spaces and punctuation) so we don't want to use them. */
  389. void
  390. handlekern() { /* an input line beginning with KPX */
  391.    register struct adobeinfo *ai ;
  392.    register char *p ;
  393.    register struct kern *nk ;
  394.  
  395.    p = paramstring() ;
  396.    if (strcmp(p,"space")==0) return ;
  397.    ai = findadobe(p) ;
  398.    if (ai == NULL)
  399.       error("! kern char not found") ;
  400.    if (ai->adobenum<'0' || ai->adobenum>'9') {
  401. /* Ignore kerns after digits because they would mess up our nice tables */
  402.       nk = newkern() ;
  403.       nk->succ = paramnewstring() ;
  404.       if (strcmp(nk->succ,"space")==0) return ;
  405.       nk->delta = transform(paramnum(),0) ;
  406.       nk->next = ai->kerns ;
  407.       ai->kerns = nk ;
  408.     }
  409. }
  410.  
  411. void
  412. handleconstruct() { /* an input line beginning with CC */
  413.    register struct adobeinfo *ai, *aci ;
  414.    register char *p ;
  415.    register struct pcc *np ;
  416.    register struct lig *nl ;
  417.    register int n ;
  418.    struct pcc *npp = NULL;
  419.  
  420.    p = paramstring() ;
  421.    ai = findadobe(p) ;
  422.    if (ai == NULL)
  423.       error("! composite character name not found") ;
  424.    n = paramnum() ;
  425.    expect(";") ;
  426.    while (n--) {
  427.       if (strcmp(paramstring(),"PCC") != 0) return ;
  428.         /* maybe I should expect("PCC") instead, but I'm playing it safe */
  429.       np = newpcc() ;
  430.       np->partname = paramnewstring() ;
  431.       if (findadobe(np->partname)==NULL) return ;
  432.       np->xoffset = paramnum() ;
  433.       np->yoffset = paramnum() ;
  434.       np->xoffset = transform(np->xoffset, np->yoffset) ;
  435.       if (npp) npp->next = np ;
  436.       else ai->pccs = np ;
  437.       npp = np ;
  438.       expect(";") ;
  439.    }
  440.    if (aci=findadobe(p+1)) { /* accented character will be a ligature too */
  441.       nl = newlig() ;
  442.       nl->succ = mymalloc(2) ;
  443.       *(nl->succ + 1) = 0 ;
  444.       *(nl->succ) = *p ;
  445.       nl->sub = ai->adobename ;
  446.       nl->next = aci->ligs ;
  447.       aci->ligs = nl ;
  448.    }
  449. }
  450.  
  451. void
  452. readadobe() {
  453.    while (getline()) {
  454.       switch(interest(paramstring())) {
  455. case FontName:
  456.          fontname = paramnewstring() ;
  457.          break ;
  458. case EncodingScheme:
  459.          codingscheme = paramnewstring() ;
  460.          break ;
  461. case ItalicAngle:
  462.          italicangle = paramfloat() ;
  463.          break ;
  464. case IsFixedPitch:
  465.          if (*param == 't' || *param == 'T')
  466.             fixedpitch = 1 ;
  467.          else
  468.             fixedpitch = 0 ;
  469.          break ;
  470. case XHeight:
  471.          xheight = paramnum() ;
  472.          break ;
  473. case C:
  474.          handlechar() ;
  475.          break ;
  476. case KPX:
  477.          handlekern() ;
  478.          break ;
  479. case CC:
  480.          handleconstruct() ;
  481.          break ;
  482. default:
  483.          break ;
  484.       }
  485.    }
  486. }
  487.  
  488. void
  489. assignchars() {
  490.    register char **p ;
  491.    register int i ;
  492.    register struct adobeinfo *ai ;
  493.    int nextfree = 128 ;
  494.  
  495. /*
  496.  *   First, we assign all those that match perfectly.
  497.  */
  498.    for (i=0, p=texencoding; i<128; i++, p++)
  499.       if (ai=findadobe(*p)) {
  500.          ai->texnum = i ;
  501.          texptrs[i] = ai ;
  502.       }
  503. /*
  504.  *   Next, we assign all the others whose codes are above 127, retaining
  505.  *   the adobe positions. */
  506.    for (ai=adobechars; ai; ai=ai->next)
  507.       if (ai->adobenum > 127 && ai->texnum<0) {
  508.          ai->texnum = ai->adobenum ;
  509.          texptrs[ai->adobenum] = ai ;
  510.       }
  511. /*   Finally, we map all remaining characters into free locations beginning
  512.  *   with 128, if we know how to construct those characters. */
  513.    for (ai=adobechars; ai; ai=ai->next)
  514.       if (ai->texnum<0 && (ai->adobenum>=0 || ai->pccs !=NULL)) {
  515.          while (texptrs[nextfree]) {
  516.             nextfree=(nextfree+1)&255 ;
  517.             if (nextfree==128) return ; /* all slots full */
  518.          }
  519.          ai->texnum = nextfree ;
  520.          texptrs[nextfree] = ai ;
  521.       }
  522. }
  523.  
  524. void
  525. upmap() { /* Compute uppercase mapping, when making a small caps font */
  526.    register struct adobeinfo *ai, *Ai ;
  527.    register char *p, *q ;
  528.    register struct pcc *np, *nq ;
  529.    char lwr[50] ;
  530.    register int n ;
  531.  
  532.    for (Ai=adobechars; Ai; Ai=Ai->next) {
  533.       p = Ai->adobename ;
  534.       if (*p>='A' && *p<='Z') {
  535.          q = lwr ;
  536.          for (; *p; p++)
  537.             *q++ = ((*p>='A' && *p<='Z') ? *p+32 : *p) ;
  538.          *q = 0;
  539.          if (ai=findadobe(lwr)) {
  540.             if (ai->texnum>=0) uppercase[ai->texnum] = Ai ;
  541.             if (Ai->texnum>=0) lowercase[Ai->texnum] = ai ;
  542.          }
  543.       }
  544.    }
  545. /* Note that, contrary to the normal true/false conventions,
  546.  * uppercase[i] is NULL and lowercase[i] is non-NULL when i is the
  547.  * ASCII code of an uppercase letter; and vice versa for lowercase letters */
  548.  
  549.    if (ai=findadobe("germandbls"))
  550.       if (Ai=findadobe("S")) { /* we also construct SS */
  551.          uppercase[ai->texnum] = ai ;
  552.          ai->width = Ai->width << 1 ;
  553.          ai->llx = Ai->llx ;
  554.          ai->lly = Ai->lly ;
  555.          ai->urx = Ai->width + Ai->urx ;
  556.          ai->ury = Ai->ury ;
  557.          ai->kerns = Ai->kerns ;
  558.          np = newpcc() ;
  559.          np->partname = "S" ;
  560.          nq = newpcc() ;
  561.          nq->partname = "S" ;
  562.          nq->xoffset = Ai->width ;
  563.          np->next = nq ;   
  564.          ai->pccs = np ;
  565.       }
  566.    if (ai=findadobe("dotlessi"))
  567.       uppercase[ai->texnum] = findadobe("I") ;
  568.    if (ai=findadobe("dotlessj"))
  569.       uppercase[ai->texnum] = findadobe("J") ;
  570. }
  571. /* The logic above seems to work well enough, but it leaves useless characters
  572.  * like `fi' and `fl' in the font if they were present initially,
  573.  * and it omits characters like `dotlessj' if they are absent initially */
  574.  
  575. /* Now we turn to computing the TFM file */
  576.  
  577. int lf, lh, nw, nh, nd, ni, nl, nk, ne, np ;
  578.  
  579. void
  580. write16(what)
  581. register short what ;
  582. {
  583.    (void)fputc(what >> 8, tfmout) ;
  584.    (void)fputc(what & 255, tfmout) ;
  585. }
  586.  
  587. void
  588. writearr(p, n)
  589. register long *p ;
  590. register int n ;
  591. {
  592.    while (n) {
  593.       write16((short)(*p >> 16)) ;
  594.       write16((short)(*p & 65535)) ;
  595.       p++ ;
  596.       n-- ;
  597.    }
  598. }
  599.  
  600. void
  601. makebcpl(p, s, n)
  602. register long *p ;
  603. register char *s ;
  604. register int n ;
  605. {
  606.    register long t ;
  607.    register long sc ;
  608.  
  609.    if (strlen(s) < n)
  610.       n = strlen(s) ;
  611.    t = ((long)n) << 24 ;
  612.    sc = 16 ;
  613.    while (n > 0) {
  614.       t |= ((long)(*(unsigned char *)s++)) << sc ;
  615.       sc -= 8 ;
  616.       if (sc < 0) {
  617.          *p++ = t ;
  618.          t = 0 ;
  619.          sc = 24 ;
  620.       }
  621.       n-- ;
  622.    }
  623.    *p++ = t ;
  624. }
  625.  
  626. int source[257] ;
  627. int unsort[257] ;
  628.  
  629. /*
  630.  *   Next we need a routine to reduce the number of distinct dimensions
  631.  *   in a TFM file. Given an array what[0]...what[oldn-1], we want to
  632.  *   group its elements into newn clusters, in such a way that the maximum
  633.  *   difference between elements of a cluster is as small as possible.
  634.  *   Furthermore, what[0]=0, and this value must remain in a cluster by
  635.  *   itself. Data such as `0 4 6 7 9' with newn=3 shows that an iterative
  636.  *   scheme in which 6 is first clustered with 7 will not work. So we
  637.  *   borrow a neat algorithm from METAFONT to find the true optimum.
  638.  *   Memory location what[oldn] is set to 0x7fffffffL for convenience.
  639.  */
  640. long nextd ; /* smallest value that will give a different mincover */
  641. int
  642. mincover(what,d) /* tells how many clusters result, given max difference d */
  643. register long d ;
  644. long *what ;
  645. {
  646.    register int m ;
  647.    register long l ;
  648.    register long *p ;
  649.  
  650.    nextd = 0x7fffffffL ;
  651.    p = what+1 ;
  652.    m = 1 ;
  653.    while (*p<0x7fffffffL) {
  654.       m++ ;
  655.       l = *p ;
  656.       while (*++p <= l+d) ;
  657.       if (*p-l < nextd) nextd = *p-l ;
  658.    }
  659.    return (m) ;
  660. }
  661.  
  662. void
  663. remap(what, oldn, newn)
  664. long *what ;
  665. int oldn, newn ;
  666. {
  667.    register int i, j ;
  668.    register long d, l ;
  669.  
  670.    what[oldn] = 0x7fffffffL ;
  671.    for (i=oldn-1; i>0; i--) {
  672.       d = what[i] ;
  673.       for (j=i; what[j+1]<d; j++) {
  674.          what[j] = what[j+1] ;
  675.          source[j] = source[j+1] ;
  676.       }
  677.       what[j] = d ;
  678.       source[j] = i ;
  679.    } /* Tom, don't let me ever catch you using bubblesort again! -- Don */
  680.  
  681.    i = mincover(what, 0L) ;
  682.    d = nextd ;
  683.    while (mincover(what,d+d)>newn) d += d ;
  684.    while (mincover(what,d)>newn) d = nextd ;
  685.  
  686.    i = 1 ;
  687.    j = 0 ;
  688.    while (i<oldn) {
  689.       j++ ;
  690.       l = what[i] ;
  691.       unsort[source[i]] = j ;
  692.       while (what[++i] <= l+d) {
  693.          unsort[source[i]] = j ;
  694.          if (i-j == oldn-newn) d = 0 ;
  695.       }
  696.       what[j] = (l+what[i-1])/2 ;
  697.    }
  698. }
  699.  
  700. /*
  701.  *   The next routine simply scales something.
  702.  *   Input is in 1000ths of an em.  Output is in FIXFACTORths of 1000.
  703.  */
  704. #define FIXFACTOR (0x100000L) /* 2^{20}, the unit fixnum */
  705. long
  706. scale(what)
  707. long what ;
  708. {
  709.    return(((what / 1000) << 20) +
  710.           (((what % 1000) << 20) + 500) / 1000) ;
  711. }
  712.  
  713. long *header, *charinfo, *width, *height, *depth, *ligkern, *kern, *tparam,
  714.      *italic ;
  715. long tfmdata[10000] ;
  716.  
  717. void
  718. buildtfm() {
  719.    register int i, j ;
  720.    register struct adobeinfo *ai ;
  721.    double tan() ;
  722.  
  723.    header = tfmdata ;
  724.    header[0] = cksum ;
  725.    header[1] = 0xa00000 ; /* 10pt design size */
  726.    makebcpl(header+2, codingscheme, 39) ;
  727.    makebcpl(header+12, fontname, 19) ;
  728.    lh = 17 ;
  729.    charinfo = header + lh ;
  730.  
  731.    for (i=0; i<256 && adobeptrs[i]==NULL; i++) ;
  732.    bc = i ;
  733.    for (i=255; i>=0 && adobeptrs[i]==NULL; i--) ;
  734.    ec = i;
  735.    if (ec < bc)
  736.       error("! no Adobe characters") ;
  737.  
  738.    width = charinfo + (ec - bc + 1) ;
  739.    width[0] = 0 ;
  740.    nw++ ;
  741.    for (i=bc; i<=ec; i++)
  742.       if (ai=adobeptrs[i]) {
  743.          width[nw]=ai->width ;
  744.          for (j=1; width[j]!=ai->width; j++) ;
  745.          ai->wptr = j ;
  746.          if (j==nw)
  747.             nw++ ;
  748.       }
  749.    if (nw>256)
  750.       error("! 256 chars with different widths") ;
  751.    depth = width + nw ;
  752.    depth[0] = 0 ;
  753.    nd = 1 ;
  754.    for (i=bc; i<=ec; i++)
  755.       if (ai=adobeptrs[i]) {
  756.          depth[nd] = -ai->lly ;
  757.          for (j=0; depth[j]!=-ai->lly; j++) ;
  758.          ai->dptr = j ;
  759.          if (j==nd)
  760.             nd++ ;
  761.       }
  762.    if (nd > 16) {
  763.       remap(depth, nd, 16) ;
  764.       nd = 16 ;
  765.       for (i=bc; i<=ec; i++)
  766.          if (ai=adobeptrs[i])
  767.             ai->dptr = unsort[ai->dptr] ;
  768.    }
  769.    height = depth + nd ;
  770.    height[0] = 0 ;
  771.    nh = 1 ;
  772.    for (i=bc; i<=ec; i++)
  773.       if (ai=adobeptrs[i]) {
  774.          height[nh]=ai->ury ;
  775.          for (j=0; height[j]!=ai->ury; j++) ;
  776.          ai->hptr = j ;
  777.          if (j==nh)
  778.             nh++ ;
  779.       }
  780.    if (nh > 16) {
  781.       remap(height, nh, 16) ;
  782.       nh = 16 ;
  783.       for (i=bc; i<=ec; i++)
  784.          if (ai=adobeptrs[i])
  785.             ai->hptr = unsort[ai->hptr] ;
  786.    }
  787.    italic  = height + nh ;
  788.    italic[0] = 0 ;
  789.    ni = 1 ;
  790.    for (i=bc; i<=ec; i++)
  791.       if (ai=adobeptrs[i]) {
  792.          italic[ni] = ai->urx - ai->width ;
  793.          if (italic[ni]<0)
  794.             italic[ni] = 0 ;
  795.          for (j=0; italic[j]!=italic[ni]; j++) ;
  796.          ai->iptr = j ;
  797.          if (j==ni)
  798.             ni++ ;
  799.       }
  800.    if (ni > 64) {
  801.       remap(italic, ni, 64) ;
  802.       ni = 64 ;
  803.       for (i=bc; i<=ec; i++)
  804.          if (ai=adobeptrs[i])
  805.             ai->iptr = unsort[ai->iptr] ;
  806.    }
  807.  
  808.    for (i=bc; i<=ec; i++)
  809.       if (ai=adobeptrs[i])
  810.          charinfo[i-bc] = ((long)(ai->wptr)<<24) +
  811.                            ((long)(ai->hptr)<<20) +
  812.                             ((long)(ai->dptr)<<16) +
  813.                              ((long)(ai->iptr)<<10) ;
  814.  
  815.    ligkern = italic + ni ;
  816.    nl = 0 ; /* ligatures and kerns omitted from raw Adobe font */
  817.    kern = ligkern + nl ;
  818.    nk = 0 ;
  819.  
  820.    newslant = (double)slant - efactor * tan(italicangle*(3.1415926535/180.0)) ;
  821.    tparam = kern + nk ;
  822.    tparam[0] = (long)(FIXFACTOR * newslant + 0.5) ;
  823.    tparam[1] = scale((long)(fontspace*efactor+0.5)) ;
  824.    tparam[2] = (fixedpitch ? 0 : scale((long)(300*efactor+0.5))) ;
  825.    tparam[3] = (fixedpitch ? 0 : scale((long)(100*efactor+0.5))) ;
  826.    tparam[4] = scale((long)xheight) ;
  827.    tparam[5] = scale((long)(1000*efactor+0.5)) ;
  828.    np = 6 ;
  829. }
  830.  
  831. void
  832. writesarr(what, len)
  833. long *what ;
  834. int len ;
  835. {
  836.    register long *p ;
  837.    int i ;
  838.  
  839.    p = what ;
  840.    i = len ;
  841.    while (i) {
  842.       *p = scale(*p) ;
  843.       p++ ;
  844.       i-- ;
  845.    }
  846.    writearr(what, len) ;
  847. }
  848.  
  849. void
  850. writetfm() {
  851.    lf = 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np ;
  852.    write16(lf) ;
  853.    write16(lh) ;
  854.    write16(bc) ;
  855.    write16(ec) ;
  856.    write16(nw) ;
  857.    write16(nh) ;
  858.    write16(nd) ;
  859.    write16(ni) ;
  860.    write16(nl) ;
  861.    write16(nk) ;
  862.    write16(ne) ;
  863.    write16(np) ;
  864.    writearr(header, lh) ;
  865.    writearr(charinfo, ec-bc+1) ;
  866.    writesarr(width, nw) ;
  867.    writesarr(height, nh) ;
  868.    writesarr(depth, nd) ;
  869.    writesarr(italic, ni) ;
  870.    writearr(ligkern, nl) ;
  871.    writesarr(kern, nk) ;
  872.    writearr(tparam, np) ;
  873. }
  874.  
  875. /* OK, the TFM file is done! Now for our next trick, the VPL file. */
  876.  
  877. /* For TeX we want to compute a character height that works properly
  878.  * with accents. The following list of accents doesn't need to be complete. */
  879. char *accents[] = { "acute", "tilde", "caron", "dieresis", NULL} ;
  880. int
  881. texheight(ai)
  882. register struct adobeinfo *ai ;
  883. {
  884.    register char **p;
  885.    register struct adobeinfo *aci, *acci ;
  886.    if (*(ai->adobename + 1)) return (ai->ury) ; /* that was the simple case */
  887.    for (p=accents; *p; p++)  /* otherwise we look for accented letters */
  888.       if (aci=findadobe(*p)) {
  889.          strcpy(buffer,ai->adobename) ;
  890.          strcat(buffer,*p) ;
  891.          if (acci=findadobe(buffer)) return (acci->ury - aci->ury + xheight) ;
  892.       }
  893.    return (ai->ury) ;
  894. }
  895.  
  896. #define vout(s)  fprintf(vplout, s)
  897. char level ; /* the depth of parenthesis nesting in VPL file being written */
  898.  
  899. void
  900. voutln(s)
  901. char *s ;
  902. {
  903.    register char l ;
  904.    fprintf(vplout,"%s\n", s) ;
  905.    for (l=level; l; l--) vout("   ") ;
  906. }
  907.  
  908. void
  909. voutln2(f,s)
  910. char *f, *s ;
  911. {
  912.    register char l ;
  913.    (void) sprintf(buffer, f, s) ;
  914.    fprintf(vplout,"%s\n", buffer) ;
  915.    for (l=level; l; l--) vout("   ") ;
  916. }
  917.  
  918. void
  919. voutln3(f,s1,s2)
  920. char *f, *s1, *s2 ;
  921. {
  922.    register char l ;
  923.    (void) sprintf(buffer, f, s1, s2) ;
  924.    fprintf(vplout,"%s\n", buffer) ;
  925.    for (l=level; l; l--) vout("   ") ;
  926. }
  927.  
  928. void
  929. vleft()
  930. {
  931.    level++ ;
  932.    vout("(") ;
  933. }
  934.  
  935. void
  936. vright()
  937. {
  938.    level-- ;
  939.    voutln(")") ;
  940. }
  941.  
  942. char vcharbuf[6] ;
  943. char *vchar(c)
  944. int c ;
  945. {
  946.    if ((c>='0' && c<='9')||(c>='A' && c<='Z')||(c>='a' && c<='z'))
  947.       (void) sprintf(vcharbuf,"C %c", c) ;
  948.    else (void) sprintf(vcharbuf,"O %o", c) ;
  949.    return (vcharbuf) ;
  950. }
  951.  
  952. void
  953. writevpl()
  954. {
  955.    register int i ;
  956.    register struct adobeinfo *ai ;
  957.    register struct lig *nlig ;
  958.    register struct kern *nkern ;
  959.    register struct pcc *npcc ;
  960.    struct adobeinfo *asucc, *asub, *api ;
  961.    int xoff, yoff, ht ;
  962.    char unlabeled ;
  963.    double tan() ;
  964.  
  965.    voutln2("(VTITLE Created by %s)", titlebuf) ;
  966.    voutln("(COMMENT Please edit that VTITLE if you edit this file)") ;
  967.    (void)sprintf(obuffer, "TeX-%s%s%s%s", outname,
  968.       (efactor==1.0? "" : "-E"), (slant==0.0? "" : "-S"),
  969.                  (makevpl==1? "" : "-CSC")) ;
  970.    if (strlen(obuffer)>19) { /* too long, will retain first 9 and last 10 */
  971.       register char *p, *q ;
  972.       for (p = &obuffer[9], q = &obuffer[strlen(obuffer)-10] ; p<&obuffer[19];
  973.               p++, q++) *p = *q ;
  974.       obuffer[19] = '\0' ;
  975.    }
  976.    voutln2("(FAMILY %s)" , obuffer) ;
  977.    voutln2("(CODINGSCHEME TeX text + %s)", codingscheme) ;
  978.    voutln("(DESIGNSIZE R 10.0)") ;
  979.    voutln("(DESIGNUNITS R 1000)") ;
  980.    voutln("(COMMENT DESIGNSIZE (1 em) IS IN POINTS)") ;
  981.    voutln("(COMMENT OTHER DIMENSIONS ARE MULTIPLES OF DESIGNSIZE/1000)") ;
  982.    voutln2("(CHECKSUM O %lo)",cksum ^ 0xffffffff) ;
  983.    vleft() ; voutln("FONTDIMEN") ;
  984.    if (newslant)
  985.       voutln2("(SLANT R %f)", newslant) ;
  986.    voutln2("(SPACE D %d)", transform(fontspace,0)) ;
  987.    if (! fixedpitch) {
  988.       voutln2("(STRETCH D %d)", transform(200,0)) ;
  989.       voutln2("(SHRINK D %d)", transform(100,0)) ;
  990.    }
  991.    voutln2("(XHEIGHT D %d)", xheight) ;
  992.    voutln2("(QUAD D %d)", transform(1000,0)) ;
  993.    voutln2("(EXTRASPACE D %d)", transform(fixedpitch ? fontspace : 111, 0)) ;
  994.    vright() ;
  995.    vleft() ; voutln("MAPFONT D 0");
  996.    voutln2("(FONTNAME %s)", outname) ;
  997.    voutln2("(FONTCHECKSUM O %lo)", cksum) ;
  998.    vright() ;
  999.    if (makevpl>1) {
  1000.       vleft() ; voutln("MAPFONT D 1");
  1001.       voutln2("(FONTNAME %s)", outname) ;
  1002.       voutln("(FONTAT D 800)") ;
  1003.       voutln2("(FONTCHECKSUM O %lo)", cksum) ;
  1004.       vright() ;
  1005.    }
  1006.  
  1007.    for (i=0; i<256 && texptrs[i]==NULL; i++) ;
  1008.    bc = i ;
  1009.    for (i=255; i>=0 && texptrs[i]==NULL; i--) ;
  1010.    ec = i;
  1011.  
  1012.    vleft() ; voutln("LIGTABLE") ;
  1013.    for (i=bc; i<=ec; i++)
  1014.       if (ai=texptrs[i]) {
  1015.          unlabeled = 1 ;
  1016.          if (uppercase[i]==NULL) /* omit ligatures from smallcap lowercase */
  1017.             for (nlig=ai->ligs; nlig; nlig=nlig->next)
  1018.                if (asucc=findadobe(nlig->succ))
  1019.                   if (asucc->texnum>=0)
  1020.                      if (asub=findadobe(nlig->sub))
  1021.                         if (asub->texnum>=0) {
  1022.                            if (unlabeled) {
  1023.                               voutln2("(LABEL %s)", vchar(i)) ;
  1024.                               unlabeled = 0 ;
  1025.                            }
  1026.                            voutln3("(LIG %s O %o)", vchar(asucc->texnum),
  1027.                                 asub->texnum) ;
  1028.                         }
  1029.          for (nkern = (uppercase[i] ? uppercase[i]->kerns : ai->kerns);
  1030.                     nkern; nkern=nkern->next)
  1031.             if (asucc=findadobe(nkern->succ))
  1032.                if (asucc->texnum>=0)
  1033.                   if (uppercase[asucc->texnum]==NULL) {
  1034.                      if (unlabeled) {
  1035.                         voutln2("(LABEL %s)", vchar(i)) ;
  1036.                         unlabeled = 0 ;
  1037.                      }
  1038.                      if (uppercase[i]) {
  1039.                         if (lowercase[asucc->texnum])
  1040.                            voutln3("(KRN %s R %.1f)",
  1041.                                  vchar(lowercase[asucc->texnum]->texnum),
  1042.                                  0.8*nkern->delta) ;
  1043.                         else voutln3("(KRN %s R %.1f)",
  1044.                                  vchar(asucc->texnum), 0.8*nkern->delta) ;
  1045.                      } else {
  1046.                         voutln3("(KRN %s R %d)", vchar(asucc->texnum),
  1047.                                 nkern->delta) ;
  1048.                         if (lowercase[asucc->texnum])
  1049.                            if (lowercase[asucc->texnum]->texnum>=0)
  1050.                               voutln3("(KRN %s R %.1f)",
  1051.                                 vchar(lowercase[asucc->texnum]->texnum),
  1052.                                 0.8*nkern->delta) ;
  1053.                      }
  1054.                   }
  1055.          if (! unlabeled) voutln("(STOP)") ;
  1056.       }
  1057.    vright() ;
  1058.  
  1059.    for (i=bc; i<=ec; i++)
  1060.       if (ai=texptrs[i]) {
  1061.          vleft() ; fprintf(vplout, "CHARACTER %s", vchar(i)) ;
  1062.          if (*vcharbuf=='C') voutln("") ;
  1063.          else voutln2(" (comment %s)", ai->adobename) ;
  1064.          if (uppercase[i]) {
  1065.             ai=uppercase[i] ;
  1066.             voutln2("(CHARWD R %.1f)", 0.8 * (ai->width)) ;
  1067.             if (ht=texheight(ai)) voutln2("(CHARHT R %.1f)", 0.8 * ht) ;
  1068.             if (ai->lly) voutln2("(CHARDP R %.1f)", -0.8 * ai->lly) ;
  1069.             if (ai->urx > ai->width)
  1070.                voutln2("(CHARIC R %.1f)", 0.8 * (ai->urx - ai->width)) ;
  1071.          } else {
  1072.             voutln2("(CHARWD R %d)", ai->width) ;
  1073.             if (ht=texheight(ai)) voutln2("(CHARHT R %d)", ht) ;
  1074.             if (ai->lly) voutln2("(CHARDP R %d)", -ai->lly) ;
  1075.             if (ai->urx > ai->width)
  1076.                voutln2("(CHARIC R %d)", ai->urx - ai->width) ;
  1077.          }
  1078.          if (ai->adobenum != i || uppercase[i]) {
  1079.             vleft() ; voutln("MAP") ;
  1080.             if (uppercase[i]) voutln("(SELECTFONT D 1)") ;
  1081.             if (ai->pccs) {
  1082.                xoff = 0 ; yoff = 0 ;
  1083.                for (npcc = ai->pccs; npcc; npcc=npcc->next)
  1084.                   if (api=findadobe(npcc->partname))
  1085.                      if (api->texnum>=0) {
  1086.                         if (npcc->xoffset != xoff) {
  1087.                            if (uppercase[i])
  1088.                               voutln2("(MOVERIGHT R %.1f)",
  1089.                                       0.8 * (npcc->xoffset - xoff)) ;
  1090.                            else voutln2("(MOVERIGHT R %d)",
  1091.                                       npcc->xoffset - xoff) ;
  1092.                            xoff = npcc->xoffset ;
  1093.                         }
  1094.                         if (npcc->yoffset != yoff) {
  1095.                            if (uppercase[i])
  1096.                               voutln2("(MOVEUP R %.1f)",
  1097.                                       0.8 * (npcc->yoffset - yoff)) ;
  1098.                            else voutln2("(MOVEUP R %d)",
  1099.                                       npcc->yoffset - yoff) ;
  1100.                            yoff = npcc->yoffset ;
  1101.                         }
  1102.                         voutln2("(SETCHAR O %o)", api->adobenum) ;
  1103.                         xoff += texptrs[api->texnum]->width ;
  1104.                      }
  1105.             } else voutln2("(SETCHAR O %o)", ai->adobenum) ;
  1106.             vright() ;
  1107.          }
  1108.          vright() ;
  1109.       }
  1110.    if (level) error("! I forgot to match the parentheses") ;
  1111. }
  1112.  
  1113. void
  1114. openfiles(argc, argv)
  1115. int argc ;
  1116. char *argv[] ;
  1117. {
  1118.    register int lastext ;
  1119.    register int i ;
  1120.  
  1121.    if (argc == 1) {
  1122.       (void)printf("afm2tfm 0.A, Copyright 1990 by Radical Eye Software\n") ;
  1123.       (void)
  1124.         printf("Usage: afm2tfm foo[.afm] [-v|-V bar[.vpl]] [foo[.tfm]]\n") ;
  1125.      exit(0) ;
  1126.    }
  1127.  
  1128.    (void)sprintf(titlebuf, "%s %s", argv[0], argv[1]) ;
  1129.    (void)strcpy(inname, argv[1]) ;
  1130.    lastext = -1 ;
  1131.    for (i=0; inname[i]; i++)
  1132.       if (inname[i] == '.')
  1133.          lastext = i ;
  1134.       else if (inname[i] == '/' || inname[i] == ':')
  1135.          lastext = -1 ;
  1136.    if (lastext == -1) (void)strcat(inname, ".afm") ;
  1137.    if ((afmin=fopen(inname, "r"))==NULL)
  1138.       error("! can't open afm input file") ;
  1139.  
  1140.    while (argc>3 && *argv[2]=='-') {
  1141.       switch (argv[2][1]) {
  1142. case 'V': makevpl++ ;
  1143. case 'v': makevpl++ ;
  1144.          (void)strcpy(outname, argv[3]) ;
  1145.          lastext = -1 ;
  1146.          for (i=0; outname[i]; i++)
  1147.             if (outname[i] == '.')
  1148.                lastext = i ;
  1149.             else if (outname[i] == '/' || outname[i] == ':')
  1150.                lastext = -1 ;
  1151.          if (lastext == -1) (void)strcat(outname, ".vpl") ;
  1152.          if ((vplout=fopen(outname, "w"))==NULL)
  1153.             error("! can't open vpl output file") ;
  1154.          break ;
  1155. case 'e': if (sscanf(argv[3], "%f", &efactor)==0 || efactor<0.01)
  1156.             error("! Bad extension factor") ;
  1157.          break ;
  1158. case 's': if (sscanf(argv[3], "%f", &slant)==0)
  1159.             error("! Bad slant parameter") ;
  1160.          break ;
  1161. default: (void)fprintf(stderr, "Unknown option %s %s will be ignored.\n",
  1162.                          argv[2], argv[3]) ;
  1163.       }
  1164.       (void)sprintf(titlebuf, "%s %s %s", titlebuf, argv[2], argv[3]) ;
  1165.       argv += 2 ;
  1166.       argc -= 2 ;
  1167.    }
  1168.  
  1169.    if (argc>3 || (argc==3 && *argv[2]=='-'))
  1170.       error("! Usage: afm2tfm foo[.afm] [-v|-V bar[.vpl]] [foo[.tfm]]") ;
  1171.          
  1172.    if (argc == 2) (void)strcpy(outname, inname) ;
  1173.    else (void)strcpy(outname, argv[2]) ;
  1174.  
  1175.    lastext = -1 ;
  1176.    for (i=0; outname[i]; i++)
  1177.       if (outname[i] == '.')
  1178.          lastext = i ;
  1179.       else if (outname[i] == '/' || outname[i] == ':')
  1180.          lastext = -1 ;
  1181.    if (argc == 2) {
  1182.       outname[lastext] = 0 ;
  1183.       lastext = -1 ;
  1184.    }
  1185.    if (lastext == -1) {
  1186.       lastext = strlen(outname) ;
  1187.       (void)strcat(outname, ".tfm") ;
  1188.    }
  1189.    if ((tfmout=fopen(outname, "w"))==NULL)
  1190.       error("! can't open tfm output file") ;
  1191.    outname[lastext] = 0 ;
  1192. }
  1193.  
  1194. main(argc, argv)
  1195. int argc ;
  1196. char *argv[] ;
  1197. {
  1198.    openfiles(argc, argv) ;
  1199.    readadobe() ;
  1200.    buildtfm() ;
  1201.    writetfm() ;
  1202.    if (makevpl) {
  1203.       assignchars() ;
  1204.       if (makevpl>1) upmap() ;
  1205.       writevpl() ;
  1206.    }
  1207.    exit(0) ;
  1208.    /*NOTREACHED*/
  1209. }
  1210.